package com.gitee.wsl.io.channel.read

import com.gitee.wsl.annotation.InternalAPI
import com.gitee.wsl.ext.string.toByteArray
import kotlinx.io.Buffer
import kotlinx.io.IOException
import kotlinx.io.Source


/**
 * Channel for asynchronous reading of sequences of bytes.
 * This is a **single-reader channel**.
 *
 * Operations on this channel cannot be invoked concurrently.
 */
 interface ByteReadChannel {

     val closedCause: Throwable?

     val isClosedForRead: Boolean

    @InternalAPI
     val readBuffer: Source

    /**
     * Suspend the channel until it has [min] bytes or gets closed. Throws exception if the channel was closed with an
     * error. If there are bytes available in the channel, this function returns immediately.
     *
     * @return return `false` eof is reached, otherwise `true`.
     */
     suspend fun awaitContent(min: Int = 1): Boolean

     fun cancel(cause: Throwable?)

    fun cancel() {
        cancel(IOException("Channel was cancelled"))
    }

     companion object {
         val Empty: ByteReadChannel = object : ByteReadChannel {
            override val closedCause: Throwable? = null

            override val isClosedForRead: Boolean
                get() = true

            @InternalAPI
            override val readBuffer: Source = Buffer()

            override suspend fun awaitContent(min: Int): Boolean = false

            override fun cancel(cause: Throwable?) {
            }
        }
    }
}


/**
 * Creates a channel for reading from the specified byte array. Please note that it could use [content] directly
 * or copy its bytes depending on the platform
 */
 fun ByteReadChannel(content: ByteArray, offset: Int = 0, length: Int = content.size): ByteReadChannel {
    val source = Buffer().also {
        it.write(content, startIndex = offset, endIndex = offset + length)
    }

    return ByteReadChannel(source)
}

 fun ByteReadChannel(text: String): ByteReadChannel =
    ByteReadChannel(text.toByteArray())

fun ByteReadChannel(source: Source): ByteReadChannel = SourceByteReadChannel(source)

fun Source.toByteReadChannel() = ByteReadChannel(this)
